/**
 * 战斗事件发射器
 * 负责发射战斗相关的事件，与外部系统进行通信
 */

import { BattleContext, BattleEvent } from './types';
import { ServiceLogger } from '../../../infrastructure/logging/UnifiedLogger';
import { componentEventBus } from '../../../infrastructure/events/ComponentEventBus';
import { COMPONENT_EVENTS } from '../../../infrastructure/events/ComponentEvents';

/**
 * 战斗事件类型定义
 */
export const BATTLE_EVENTS = {
    // 战斗生命周期事件
    BATTLE_CREATED: 'battle.created',
    BATTLE_STARTED: 'battle.started',
    BATTLE_COMPLETED: 'battle.completed',
    BATTLE_CANCELLED: 'battle.cancelled',
    BATTLE_ERROR: 'battle.error',

    // 阶段事件
    PHASE_CHANGED: 'battle.phase.changed',
    ROUND_STARTED: 'battle.round.started',
    ROUND_ENDED: 'battle.round.ended',

    // 行动事件
    UNIT_ACTION: 'battle.unit.action',
    UNIT_ATTACKED: 'battle.unit.attacked',
    UNIT_SKILL_USED: 'battle.unit.skill_used',
    UNIT_DEFENDED: 'battle.unit.defended',

    // 状态变化事件
    UNIT_DAMAGED: 'battle.unit.damaged',
    UNIT_HEALED: 'battle.unit.healed',
    UNIT_DIED: 'battle.unit.died',
    UNIT_REVIVED: 'battle.unit.revived',

    // 效果事件
    BUFF_APPLIED: 'battle.buff.applied',
    BUFF_REMOVED: 'battle.buff.removed',
    AURA_ACTIVATED: 'battle.aura.activated',
    AURA_DEACTIVATED: 'battle.aura.deactivated',

    // 特殊事件
    CRITICAL_HIT: 'battle.critical_hit',
    BLOCK_SUCCESSFUL: 'battle.block_successful',
    SKILL_COOLDOWN_RESET: 'battle.skill.cooldown_reset'
} as const;

/**
 * 事件监听器接口
 */
export interface BattleEventListener {
    (eventType: string, data: any): void | Promise<void>;
}

/**
 * 战斗事件发射器
 */
export class BattleEventEmitter {
    private logger: ServiceLogger;
    private listeners = new Map<string, BattleEventListener[]>();
    private eventHistory: BattleEvent[] = [];
    private maxHistorySize = 500;

    constructor() {
        this.logger = new ServiceLogger('BattleEventEmitter');
    }

    /**
     * 发射战斗事件
     */
    async emitBattleEvent(
        eventType: string, 
        context: BattleContext, 
        data: any
    ): Promise<void> {
        try {
            // 创建事件对象
            const event: BattleEvent = {
                eventId: this.generateEventId(),
                type: eventType,
                battleId: context.state.battleId,
                round: context.state.currentRound,
                effects: [], // 根据事件类型填充
                description: this.generateEventDescription(eventType, data),
                timestamp: Date.now(),
                data
            };

            // 添加到历史记录
            this.addToHistory(event);

            this.logger.debug(`Emitting battle event: ${eventType}`, {
                metadata: {
                    battleId: context.state.battleId,
                    eventId: event.eventId,
                    round: context.state.currentRound
                }
            });

            // 发射到本地监听器
            await this.emitToLocalListeners(eventType, data);

            // 发射到全局事件总线
            await this.emitToGlobalEventBus(eventType, context, data);

            // 添加到上下文的事件历史
            context.eventHistory.push(event);

        } catch (error) {
            this.logger.error(`Failed to emit battle event: ${eventType}`, undefined, error);
        }
    }

    /**
     * 发射单位行动事件
     */
    async emitUnitAction(
        context: BattleContext,
        actorId: string,
        actionType: string,
        targetIds: string[],
        result: any
    ): Promise<void> {
        await this.emitBattleEvent(BATTLE_EVENTS.UNIT_ACTION, context, {
            actorId,
            actionType,
            targetIds,
            result,
            round: context.state.currentRound
        });
    }

    /**
     * 发射伤害事件
     */
    async emitDamage(
        context: BattleContext,
        attackerId: string,
        targetId: string,
        damage: number,
        damageType: string,
        isCritical: boolean = false
    ): Promise<void> {
        const eventType = isCritical ? BATTLE_EVENTS.CRITICAL_HIT : BATTLE_EVENTS.UNIT_DAMAGED;
        
        await this.emitBattleEvent(eventType, context, {
            attackerId,
            targetId,
            damage,
            damageType,
            isCritical,
            round: context.state.currentRound
        });
    }

    /**
     * 发射治疗事件
     */
    async emitHealing(
        context: BattleContext,
        healerId: string,
        targetId: string,
        healing: number,
        isCritical: boolean = false
    ): Promise<void> {
        await this.emitBattleEvent(BATTLE_EVENTS.UNIT_HEALED, context, {
            healerId,
            targetId,
            healing,
            isCritical,
            round: context.state.currentRound
        });
    }

    /**
     * 发射单位死亡事件
     */
    async emitUnitDeath(
        context: BattleContext,
        unitId: string,
        killerId?: string
    ): Promise<void> {
        await this.emitBattleEvent(BATTLE_EVENTS.UNIT_DIED, context, {
            unitId,
            killerId,
            round: context.state.currentRound
        });

        // 同时发射到RPG事件系统
        const participant = context.state.homeParticipants.find(p => p.id === unitId) ||
                           context.state.awayParticipants.find(p => p.id === unitId);
        
        if (participant) {
            await componentEventBus.emit(
                COMPONENT_EVENTS.RPG.BATTLE_ENDED,
                'BattleEngine',
                {
                    playerId: unitId,
                    battleResult: { defeated: true, round: context.state.currentRound }
                }
            );
        }
    }

    /**
     * 发射技能使用事件
     */
    async emitSkillUsed(
        context: BattleContext,
        casterId: string,
        skillId: string,
        targetIds: string[],
        result: any
    ): Promise<void> {
        await this.emitBattleEvent(BATTLE_EVENTS.UNIT_SKILL_USED, context, {
            casterId,
            skillId,
            targetIds,
            result,
            round: context.state.currentRound
        });

        // 发射到RPG事件系统
        const participant = context.state.homeParticipants.find(p => p.id === casterId) ||
                           context.state.awayParticipants.find(p => p.id === casterId);
        
        if (participant) {
            await componentEventBus.emit(
                COMPONENT_EVENTS.RPG.SKILL_LEARNED,
                'BattleEngine',
                {
                    playerId: casterId,
                    skill: { skillId, usedInBattle: true }
                }
            );
        }
    }

    /**
     * 发射回合事件
     */
    async emitRoundStart(context: BattleContext): Promise<void> {
        await this.emitBattleEvent(BATTLE_EVENTS.ROUND_STARTED, context, {
            round: context.state.currentRound,
            aliveParticipants: [
                ...context.state.homeParticipants.filter(p => p.isAlive),
                ...context.state.awayParticipants.filter(p => p.isAlive)
            ].map(p => ({ id: p.id, name: p.name, hp: p.component.hp_now }))
        });
    }

    /**
     * 发射回合结束事件
     */
    async emitRoundEnd(context: BattleContext): Promise<void> {
        await this.emitBattleEvent(BATTLE_EVENTS.ROUND_ENDED, context, {
            round: context.state.currentRound,
            aliveParticipants: [
                ...context.state.homeParticipants.filter(p => p.isAlive),
                ...context.state.awayParticipants.filter(p => p.isAlive)
            ].map(p => ({ id: p.id, name: p.name, hp: p.component.hp_now }))
        });
    }

    /**
     * 注册事件监听器
     */
    on(eventType: string, listener: BattleEventListener): void {
        if (!this.listeners.has(eventType)) {
            this.listeners.set(eventType, []);
        }
        this.listeners.get(eventType)!.push(listener);
        
        this.logger.debug(`Event listener registered: ${eventType}`);
    }

    /**
     * 移除事件监听器
     */
    off(eventType: string, listener: BattleEventListener): void {
        const listeners = this.listeners.get(eventType);
        if (listeners) {
            const index = listeners.indexOf(listener);
            if (index >= 0) {
                listeners.splice(index, 1);
                this.logger.debug(`Event listener removed: ${eventType}`);
            }
        }
    }

    /**
     * 获取事件历史
     */
    getEventHistory(battleId?: string): BattleEvent[] {
        if (battleId) {
            return this.eventHistory.filter(event => event.battleId === battleId);
        }
        return [...this.eventHistory];
    }

    /**
     * 清理事件历史
     */
    clearEventHistory(battleId?: string): void {
        if (battleId) {
            this.eventHistory = this.eventHistory.filter(event => event.battleId !== battleId);
        } else {
            this.eventHistory = [];
        }
        this.logger.debug(`Event history cleared${battleId ? ` for battle: ${battleId}` : ''}`);
    }

    // ==================== 私有方法 ====================

    /**
     * 发射到本地监听器
     */
    private async emitToLocalListeners(eventType: string, data: any): Promise<void> {
        const listeners = this.listeners.get(eventType) || [];
        
        const emitPromises = listeners.map(async listener => {
            try {
                await listener(eventType, data);
            } catch (error) {
                this.logger.error(`Local listener failed for event: ${eventType}`, undefined, error);
            }
        });

        await Promise.allSettled(emitPromises);
    }

    /**
     * 发射到全局事件总线
     */
    private async emitToGlobalEventBus(eventType: string, context: BattleContext, data: any): Promise<void> {
        try {
            // 根据事件类型映射到相应的组件事件
            const componentEvent = this.mapToComponentEvent(eventType);
            if (componentEvent) {
                await componentEventBus.emit(componentEvent, 'BattleEngine', {
                    battleId: context.state.battleId,
                    round: context.state.currentRound,
                    eventType,
                    ...data
                });
            }
        } catch (error) {
            this.logger.error(`Failed to emit to global event bus: ${eventType}`, undefined, error);
        }
    }

    /**
     * 映射到组件事件
     */
    private mapToComponentEvent(battleEventType: string): string | null {
        const mapping: Record<string, string> = {
            [BATTLE_EVENTS.BATTLE_STARTED]: COMPONENT_EVENTS.RPG.BATTLE_STARTED,
            [BATTLE_EVENTS.BATTLE_COMPLETED]: COMPONENT_EVENTS.RPG.BATTLE_ENDED,
            [BATTLE_EVENTS.UNIT_DIED]: COMPONENT_EVENTS.RPG.HP_CHANGED,
            [BATTLE_EVENTS.UNIT_SKILL_USED]: COMPONENT_EVENTS.RPG.SKILL_LEARNED
        };

        return mapping[battleEventType] || null;
    }

    /**
     * 生成事件描述
     */
    private generateEventDescription(eventType: string, data: any): string {
        switch (eventType) {
            case BATTLE_EVENTS.BATTLE_STARTED:
                return `战斗开始 - 参与者数量: ${data.participants?.length || 0}`;
            case BATTLE_EVENTS.BATTLE_COMPLETED:
                return `战斗结束 - 结果: ${data.result?.resultType || 'unknown'}`;
            case BATTLE_EVENTS.ROUND_STARTED:
                return `第${data.round}回合开始`;
            case BATTLE_EVENTS.ROUND_ENDED:
                return `第${data.round}回合结束`;
            case BATTLE_EVENTS.UNIT_ACTION:
                return `${data.actorId} 执行 ${data.actionType}`;
            case BATTLE_EVENTS.UNIT_DAMAGED:
                return `${data.targetId} 受到 ${data.damage} 点伤害`;
            case BATTLE_EVENTS.UNIT_HEALED:
                return `${data.targetId} 恢复 ${data.healing} 点生命`;
            case BATTLE_EVENTS.UNIT_DIED:
                return `${data.unitId} 被击败`;
            case BATTLE_EVENTS.CRITICAL_HIT:
                return `${data.attackerId} 对 ${data.targetId} 造成暴击！`;
            default:
                return `战斗事件: ${eventType}`;
        }
    }

    /**
     * 生成事件ID
     */
    private generateEventId(): string {
        return `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }

    /**
     * 添加到历史记录
     */
    private addToHistory(event: BattleEvent): void {
        this.eventHistory.push(event);
        
        // 保持历史记录大小
        if (this.eventHistory.length > this.maxHistorySize) {
            this.eventHistory.shift();
        }
    }
}
